import asyncio
import json
import websockets
import aiohttp
from typing import Dict, Any, Optional, Callable


class GameClient:
    """游戏客户端网络层"""
    
    def __init__(self):
        self.websocket = None
        self.connected = False
        self.room_id = None
        self.player_id = None
        self.game_state = None
        self.message_handlers = {}
        self.error_callback = None  # Callback for displaying errors in UI
        self.animation_callback = None  # Callback for triggering animations
        self.game_over_callback = None  # Callback for game over events
        self.available_decks = []  # Available deck list
        
        # 注册默认消息处理器
        self.register_handler("JOIN_SUCCESS", self._handle_join_success)
        self.register_handler("AVAILABLE_DECKS", self._handle_available_decks)
        self.register_handler("SELECT_DECK_RESULT", self._handle_select_deck_result)
        self.register_handler("STATE_UPDATE", self._handle_state_update)
        self.register_handler("MULLIGAN_RESULT", self._handle_mulligan_result)
        self.register_handler("SUMMON_RESULT", self._handle_summon_result)
        self.register_handler("USE_ITEM_RESULT", self._handle_use_item_result)
        self.register_handler("ATTACK_RESULT", self._handle_attack_result)
        self.register_handler("END_TURN_RESULT", self._handle_end_turn_result)
        self.register_handler("GAME_OVER", self._handle_game_over)
        self.register_handler("ERROR", self._handle_error)
        self.register_handler("PLAYER_DISCONNECTED", self._handle_player_disconnected)
        self.register_handler("SYNC_OWN_DECKS_RESULT", self._handle_sync_own_decks_result)
    
    def set_error_callback(self, callback):
        """Set callback function for error messages"""
        self.error_callback = callback
    
    def set_animation_callback(self, callback):
        """Set callback function for animations"""
        self.animation_callback = callback
    
    def set_game_over_callback(self, callback):
        """Set callback function for game over events"""
        self.game_over_callback = callback
    
    def register_handler(self, message_type: str, handler: Callable):
        """注册消息处理器"""
        self.message_handlers[message_type] = handler
    
    async def connect(self, server_url: str, room_id: str, player_id: str) -> bool:
        """连接到服务器"""
        try:
            self.room_id = room_id
            self.player_id = player_id
            self.websocket = await websockets.connect(f"{server_url}/ws/{room_id}/{player_id}")
            self.connected = True
            
            # 启动消息接收循环
            asyncio.create_task(self._message_loop())
            
            return True
        except Exception as e:
            print(f"Connection failed: {e}")
            self.connected = False
            return False
    
    async def disconnect(self):
        """断开连接"""
        if self.websocket:
            await self.websocket.close()
        self.connected = False
    
    async def _message_loop(self):
        """消息接收循环"""
        try:
            async for message in self.websocket:
                try:
                    data = json.loads(message)
                    message_type = data.get("type")
                    
                    if message_type in self.message_handlers:
                        print(f"DEBUG: Processing message type: {message_type}")
                        await self.message_handlers[message_type](data)
                    else:
                        print(f"Unknown message type: {message_type}")
                
                except json.JSONDecodeError:
                    print(f"Invalid JSON message: {message}")
                except Exception as e:
                    print(f"Error processing message: {e}")
        
        except websockets.exceptions.ConnectionClosed:
            print("Connection closed")
            self.connected = False
        except Exception as e:
            print(f"Message loop error: {e}")
            self.connected = False
    
    async def _send_message(self, message: Dict[str, Any]):
        """发送消息到服务器"""
        if self.websocket and self.connected:
            try:
                await self.websocket.send(json.dumps(message))
            except Exception as e:
                print(f"Failed to send message: {e}")
    
    async def send_select_deck(self, deck_name: str):
        """发送选择卡组操作"""
        await self._send_message({
            "type": "SELECT_DECK",
            "deck_name": deck_name
        })
    
    async def send_sync_own_decks(self):
        """发送同步自定义卡组消息"""
        try:
            import os
            import json
            
            # 读取本地自定义卡组
            owndeck_dir = os.path.join(os.path.dirname(__file__), "owndeck")
            custom_decks = []
            
            if os.path.exists(owndeck_dir):
                for filename in os.listdir(owndeck_dir):
                    if filename.endswith('.json'):
                        filepath = os.path.join(owndeck_dir, filename)
                        try:
                            with open(filepath, "r", encoding="utf-8") as f:
                                deck_data = json.load(f)
                                # 添加name字段用于识别
                                deck_data["name"] = os.path.splitext(filename)[0]
                                custom_decks.append(deck_data)
                        except Exception as e:
                            print(f"Failed to load custom deck {filename}: {e}")
            
            await self._send_message({
                "type": "SYNC_OWN_DECKS",
                "decks": custom_decks
            })
            
        except Exception as e:
            print(f"Error syncing custom decks: {e}")
            if self.error_callback:
                self.error_callback(f"Failed to sync custom decks: {e}", "red")
    
    async def send_mulligan(self, cards: list):
        """发送换牌操作"""
        await self._send_message({
            "type": "MULLIGAN",
            "cards": cards
        })
    
    async def send_summon(self, card_id: str, position: int, guard_target: Optional[str] = None, effect_target: Optional[str] = None):
        """发送召唤操作"""
        message = {
            "type": "SUMMON",
            "card_id": card_id,
            "position": position,
            "guard_target": guard_target
        }
        if effect_target:
            message["effect_target"] = effect_target
        await self._send_message(message)
    
    async def send_use_item(self, card_id: str, target_id: Optional[str] = None):
        """发送使用物品操作"""
        await self._send_message({
            "type": "USE_ITEM",
            "card_id": card_id,
            "target_id": target_id
        })
    
    async def send_attack(self, attacker_id: str, target_id: str):
        """发送攻击操作"""
        await self._send_message({
            "type": "ATTACK",
            "attacker_id": attacker_id,
            "target_id": target_id
        })
    
    async def send_end_turn(self):
        """发送结束回合操作"""
        await self._send_message({
            "type": "END_TURN"
        })
    
    # 消息处理器
    async def _handle_join_success(self, data: Dict[str, Any]):
        """处理加入成功消息"""
        print(f"Joined room successfully: {data.get('data', {}).get('message', '')}")
        print(f"DEBUG: game_initialized = {data.get('data', {}).get('game_initialized')}")
        # 无论游戏是否初始化，都同步自定义卡组
        print("DEBUG: Starting to sync custom decks...")
        await self.send_sync_own_decks()
    
    async def _handle_available_decks(self, data: Dict[str, Any]):
        """处理可用卡组列表消息"""
        decks_data = data.get("data", {})
        self.available_decks = decks_data.get("decks", [])
        print(f"Received {len(self.available_decks)} available decks")
        # 调试：显示卡组详情
        for i, deck in enumerate(self.available_decks):
            print(f"  Deck {i+1}: {deck.get('name', 'Unknown')} ({deck.get('title', 'Unknown')}) - Custom: {deck.get('is_custom', False)}")
    
    async def _handle_select_deck_result(self, data: Dict[str, Any]):
        """处理选择卡组结果"""
        result = data.get("data", {})
        if result.get("success"):
            print(f"Deck selected: {result.get('message', '')}")
        else:
            print(f"Deck selection failed: {result.get('error', '')}")
    
    async def _handle_state_update(self, data: Dict[str, Any]):
        """处理状态更新消息(包含动画事件)"""
        self.game_state = data.get("data", {})
        
        # 检查游戏阶段变化，控制背景音乐
        game_phase = self.game_state.get("game_phase", "")
        if game_phase == "PLAYING" and not getattr(self, 'music_started', False):
            # 游戏开始，启动背景音乐
            if hasattr(self, 'start_background_music'):
                self.start_background_music()
            self.music_started = True
        elif game_phase in ["ENDED", "DECK_SELECTION", "MULLIGAN"] and getattr(self, 'music_started', False):
            # 游戏结束或回到其他阶段，停止背景音乐
            if hasattr(self, 'stop_background_music'):
                self.stop_background_music()
            self.music_started = False
        
        # 处理动画事件
        animations = data.get("animations", [])
        if animations and self.animation_callback:
            for anim in animations:
                anim_type = anim.get('type')
                anim_data = anim.get('data', {})
                self.animation_callback(anim_type, anim_data)
        
        print("Game state updated")
    
    async def _handle_mulligan_result(self, data: Dict[str, Any]):
        """处理换牌结果"""
        result = data.get("data", {})
        if result.get("success"):
            print("Mulligan successful")
        else:
            print(f"Mulligan failed: {result.get('error', '')}")
    
    async def _handle_summon_result(self, data: Dict[str, Any]):
        """处理召唤结果"""
        result = data.get("data", {})
        if result.get("success"):
            message = result.get('message', 'Summoned successfully')
            print(f"Summon successful: {message}")
            if self.error_callback:
                self.error_callback(message, "green")
            
            # 不再在这里触发动画，动画统一由服务器广播触发
        else:
            error_msg = result.get('error', 'Unknown error')
            print(f"Summon failed: {error_msg}")
            if self.error_callback:
                self.error_callback(error_msg, "red")
    
    async def _handle_use_item_result(self, data: Dict[str, Any]):
        """处理使用物品结果"""
        result = data.get("data", {})
        if result.get("success"):
            # 检查是否需要选择（Flag道具）
            if result.get("effect") == "choice_required":
                # 设置Flag选择状态
                if hasattr(self, 'set_flag_choice_required'):
                    self.set_flag_choice_required(result.get("choices", []))
                print("Flag choice required")
            else:
                message = result.get('message', 'Item used successfully')
                print(f"Item used successfully: {message}")
                if self.error_callback:
                    self.error_callback(message, "green")
                
                # 不再在这里触发动画，动画统一由服务器广播触发
        else:
            error_msg = result.get('error', 'Unknown error')
            print(f"Failed to use item: {error_msg}")
            if self.error_callback:
                self.error_callback(error_msg, "red")
    
    async def _handle_attack_result(self, data: Dict[str, Any]):
        """处理攻击结果"""
        result = data.get("data", {})
        if result.get("success"):
            print(f"Attack successful: dealt {result.get('attacker_damage', 0)} damage")
            
            # 不再在这里触发动画，动画统一由服务器广播触发
        else:
            error_msg = result.get('error', 'Unknown error')
            print(f"Attack failed: {error_msg}")
            if self.error_callback:
                self.error_callback(error_msg, "red")
    
    async def _handle_end_turn_result(self, data: Dict[str, Any]):
        """处理结束回合结果"""
        result = data.get("data", {})
        if result.get("success"):
            print("Turn ended")
        else:
            error_msg = result.get('error', 'Unknown error')
            print(f"Failed to end turn: {error_msg}")
            if self.error_callback:
                self.error_callback(error_msg, "red")
    
    async def _handle_game_over(self, data: Dict[str, Any]):
        """处理游戏结束消息"""
        result = data.get("data", {})
        message = result.get('message', 'Game over')
        print(f"Game over: {message}")
        
        # 调用游戏结束回调
        if self.game_over_callback:
            self.game_over_callback(result)
        
        if self.error_callback:
            self.error_callback(message, "yellow")
    
    async def _handle_error(self, data: Dict[str, Any]):
        """处理错误消息"""
        message = data.get("message", "Unknown error")
        print(f"Error: {message}")
        
        # 如果是房间已满的错误，断开连接
        if "Room is full" in message:
            await self.disconnect()
        
        if self.error_callback:
            self.error_callback(message, "red")
    
    async def _handle_player_disconnected(self, data: Dict[str, Any]):
        """处理玩家断开连接消息"""
        player_id = data.get("player_id", "Unknown player")
        print(f"Player {player_id} disconnected")
    
    def get_game_state(self) -> Optional[Dict[str, Any]]:
        """获取当前游戏状态"""
        return self.game_state
    
    def is_my_turn(self) -> bool:
        """是否是我的回合"""
        if not self.game_state:
            return False
        return self.game_state.get("current_player") == self.player_id
    
    def get_my_hand(self) -> list:
        """获取我的手牌"""
        if not self.game_state:
            return []
        return self.game_state.get("players", {}).get(self.player_id, {}).get("hand", [])
    
    def get_my_battlefield(self) -> list:
        """获取我的场地"""
        if not self.game_state:
            return []
        return self.game_state.get("players", {}).get(self.player_id, {}).get("battlefield", [])
    
    def get_opponent_id(self) -> Optional[str]:
        """获取对手ID"""
        if not self.game_state:
            return None
        players = self.game_state.get("players", {})
        for pid in players.keys():
            if pid != self.player_id:
                return pid
        return None
    
    def get_opponent_battlefield(self) -> list:
        """获取对手的场地"""
        if not self.game_state:
            return []
        # 找到对手ID
        opponent_id = self.get_opponent_id()
        if not opponent_id:
            return []
        return self.game_state.get("players", {}).get(opponent_id, {}).get("battlefield", [])
    
    def get_mulligan_cards(self) -> list:
        """获取换牌阶段的卡牌"""
        if not self.game_state:
            return []
        return self.game_state.get("mulligan_cards", [])
    
    def is_mulligan_phase(self) -> bool:
        """是否在换牌阶段"""
        if not self.game_state:
            return False
        return self.game_state.get("game_phase") == "MULLIGAN"
    
    def is_deck_selection_phase(self) -> bool:
        """是否在卡组选择阶段"""
        if not self.game_state:
            return False
        return self.game_state.get("game_phase") == "DECK_SELECTION"
    
    def is_playing_phase(self) -> bool:
        """是否在游戏阶段"""
        if not self.game_state:
            return False
        return self.game_state.get("game_phase") == "PLAYING"
    
    def get_available_decks(self) -> list:
        """获取可用卡组列表"""
        return self.available_decks
    
    async def _handle_sync_own_decks_result(self, data: Dict[str, Any]):
        """处理同步自定义卡组结果"""
        result = data.get("data", {})
        if result.get("success"):
            print(f"Successfully synced {result.get('deck_count', 0)} custom decks")
        else:
            print(f"Failed to sync custom decks: {result.get('error', 'Unknown error')}")
            if self.error_callback:
                self.error_callback(f"Sync failed: {result.get('error', 'Unknown error')}", "red")
    
    async def send_flag_choice(self, choice_id: str):
        """发送Flag选择结果"""
        if not self.connected or not self.websocket:
            return
        
        message = {
            "type": "USE_ITEM_WITH_CHOICE",
            "card_id": "flag",
            "choice_id": choice_id
        }
        
        await self.websocket.send(json.dumps(message))
    
    async def fetch_rooms(self, server_url: str) -> Optional[Dict[str, Any]]:
        """获取房间列表"""
        try:
            # 将WebSocket URL转换为HTTP URL
            http_url = server_url.replace("ws://", "http://").replace("wss://", "https://")
            api_url = f"{http_url}/api/rooms"
            
            # 设置超时时间
            timeout = aiohttp.ClientTimeout(total=5)  # 5秒超时
            
            async with aiohttp.ClientSession(timeout=timeout) as session:
                async with session.get(api_url) as response:
                    if response.status == 200:
                        data = await response.json()
                        return data
                    else:
                        print(f"Failed to fetch rooms: HTTP {response.status}")
                        return None
        except asyncio.TimeoutError:
            print("Timeout while fetching rooms")
            return None
        except Exception as e:
            print(f"Error fetching rooms: {e}")
            return None
